//-------------------------------------------------------------------
//	Copyright (c) 2010-2011  Zhirnov Andrey
//	This file is part of the "UXGEN_ResourceConverter" project.
//	See copyright notice in "Converter.h".
//-------------------------------------------------------------------

#include "CSpriteConverter.h"
#include "..\\..\\Core\\CConverter.h"
#include "ILWrapper.h"

#undef RGB

struct TRed
{
	uint8	uR;
	///
	TRed(): uR(0)					{}
	TRed(uint8 r): uR(r)			{}

	uint8 & R()						{ return uR; }
};


struct TRG
{
	uint8	aRG[2];
	///
	TRG()							{ aRG[0] = 0; aRG[1] = 0; }
	TRG(uint8 r, uint g)			{ aRG[0] = r; aRG[1] = g; }

	uint8 & R()						{ return aRG[1]; }
	uint8 & G()						{ return aRG[0]; }
};


struct TRGB
{
	uint8	aRGB[3];
	///
	TRGB()							{ memset( aRGB, 0, sizeof(aRGB) ); }
	TRGB(uint8 r, uint8 g, uint8 b)	{ aRGB[0] = r; aRGB[1] = g; aRGB[2] = b; }

	uint8 & R()					{ return aRGB[2]; }
	uint8 & G()					{ return aRGB[1]; }
	uint8 & B()					{ return aRGB[0]; }

	TRG 	RG()				{ return TRG( R(), G() ); }
	TRG		GB()				{ return TRG( G(), B() ); }
};


union TRGBA
{
	uint8	aRGBA[4];
	uint32	uRGBA;
	///
	TRGBA(): uRGBA(0)							{}
	TRGBA(uint32 v): uRGBA(v)					{}
	TRGBA(uint8 r, uint8 g, uint8 b, uint8 a)	{ aRGBA[0] = r; aRGBA[1] = g; aRGBA[2] = b; aRGBA[3] = a; }

	uint8 & R()					{ return aRGBA[3]; }
	uint8 & G()					{ return aRGBA[2]; }
	uint8 & B()					{ return aRGBA[1]; }
	uint8 & A()					{ return aRGBA[0]; }

	TRG		RG()				{ return TRG( R(), G() ); }
	TRGB	RGB()				{ return TRGB( R(), G(), B() ); }
};



CSpriteConverter::CSpriteConverter():
	_bConverted(false), _eFormat(e_tex_format::UNKNOWN), _eSwizzle(e_tex_swizzle::AUTO)
{
}


CSpriteConverter::~CSpriteConverter()
{
}


HRESULT CALLBACK CSpriteConverter::GetType(E_SUBSYSTEM_TYPE &eType)
{
	eType = SST_SPRITE_CONVERTER;
	return S_OK;
}


HRESULT CALLBACK CSpriteConverter::GetSupportedFormats(char *pBuffer, uint uCount)
{
	return SYSTEMS->pTexConv->GetSupportedFormats( pBuffer, uCount );
}


HRESULT CALLBACK CSpriteConverter::Create()
{
	_sInfo.Clear();
	_sSprite.Clear();
	_aTextures.Clear();
	_sParams	= TSpriteParams();
	_eFormat	= e_tex_format::UNKNOWN;
	_eSwizzle	= e_tex_swizzle::AUTO;
	_bConverted	= false;
	return S_OK;
}


HRESULT CALLBACK CSpriteConverter::Delete()
{
	return Create();
}


HRESULT CALLBACK CSpriteConverter::Build()
{
	if ( _bConverted )
		return S_OK;

	uvec2		s_last_dim;

	for (uint i = 0; i < 4 && !_bConverted; ++i)
	{
		_bConverted = _Convert( _sSprite, s_last_dim );
	}

	return _bConverted ? S_OK : E_FAIL;
}


HRESULT CALLBACK CSpriteConverter::Save(const char *pFileName)
{
	IFilePtr	p_file = nullptr;
	
	_sInfo.Clear();

	if ( CORE->LoadFile( pFileName, p_file, e_file_open_flags::DEF_WRITE ) != S_OK ||
		 Build() != S_OK )
	{
		return E_FAIL;
	}

	bool	ret = Loaders::SaveSprite2D( p_file, _sSprite );

	return ret ? S_OK : E_FAIL;
}


HRESULT CALLBACK CSpriteConverter::AddTexture(const char *pFileName, uint &uNumb)
{
	E_TEXTURE_TYPE	e_type;
	TImage2D		s_image;

	if ( SYSTEMS->pIL->LoadTexture( pFileName, e_type ) &&
		 SYSTEMS->pIL->GetTexture2D( s_image ) )
	{
		if ( _aTextures.Empty() && !s_image.bCompressed )
		{
			_eFormat	= s_image.eFormat;
			_eSwizzle	= s_image.eSwizzle;
		}
		else
		if ( s_image.bCompressed ||
			!Image::ComparePixelFormats( s_image.eFormat, _eFormat ) )
		{
			SYSTEMS->pIL->DeleteTexture();
			return E_FAIL;
		}

		uNumb = (uint)_aTextures.Count();
		_aTextures.PushBack( TSprImage( s_image, String::GetFileName( pFileName ) ) );
		SYSTEMS->pIL->DeleteTexture();
		_bConverted = false;
		return S_OK;
	}

	return E_FAIL;
}


HRESULT CALLBACK CSpriteConverter::RemoveTexture(uint uNumb)
{
	if ( uNumb >= _aTextures.Count() )
		return E_INVALIDARG;

	_aTextures.Erase( uNumb );
	_bConverted = false;
	return S_OK;
}


HRESULT CALLBACK CSpriteConverter::GetTexturesCount(uint &uCount)
{
	uCount = _aTextures.Count();
	return S_OK;
}


HRESULT CALLBACK CSpriteConverter::GetTextureInfo(uint uNumb, char *pBuffer, uint uCount)
{
	if ( pBuffer == nullptr || uCount == 0 || uNumb >= _aTextures.Count() )
		return E_INVALIDARG;

	string				str;
	uvec2	const		s_dim	= _aTextures[uNumb].sImage.vTexDim;
	uvec2	const		s_frame	= _aTextures[uNumb].sFrame;
	e_tex_format::type	e_fmt	= _aTextures[uNumb].sImage.eFormat;
	uint				u_frame_count = 0;

	u_frame_count = (s_dim.x/s_frame.x) * (s_dim.y/s_frame.y);

	str << "width:        " << s_dim.x << "\x00D\x00A";
	str << "height:       " << s_dim.y << "\x00D\x00A";
	
	str << "color format: " << Image::GetColorFormatName( e_fmt ) << "\x00D\x00A";
	str << "color type:   " << Image::GetColorValueTypeName( e_fmt ) << "\x00D\x00A";

	str << "frame count:  " << u_frame_count << "\x00D\x00A";
	str << "anim count:   " << _aTextures[uNumb].aAnimations.Count() << "\x00D\x00A";

	if ( uCount > str.Length() )
	{
		memcpy( pBuffer, str.cstr(), str.Size() );
		return S_OK;
	}

	return S_FALSE;
}


HRESULT CALLBACK CSpriteConverter::GetName(uint uNumb, char *pBuffer, uint uCount)
{
	if ( pBuffer == nullptr || uCount == 0 || uNumb >= _aTextures.Count() )
		return E_INVALIDARG;

	if ( uCount > _aTextures[uNumb].sName.Length() )
	{
		memcpy( pBuffer, _aTextures[uNumb].sName.cstr(), _aTextures[uNumb].sName.Size() );
		return S_OK;
	}

	return E_FAIL;
}


HRESULT CALLBACK CSpriteConverter::SetFrame(uint uNumb, uint uFrameX, uint uFrameY)
{
	if ( uNumb >= _aTextures.Count() || uFrameX == 0 || uFrameY == 0 )
		return E_INVALIDARG;

	_aTextures[uNumb].sFrame = uvec2( uFrameX, uFrameY );
	_bConverted = false;
	return S_OK;
}


HRESULT CALLBACK CSpriteConverter::GetFrame(uint uNumb, uint &uFrameX, uint &uFrameY)
{
	if ( uNumb >= _aTextures.Count() )
		return E_INVALIDARG;

	uFrameX = _aTextures[uNumb].sFrame.x;
	uFrameY = _aTextures[uNumb].sFrame.y;
	return S_OK;
}


HRESULT CALLBACK CSpriteConverter::SetAnimation(uint uNumb, const char *pAnimName, float fFrameRate, const TSpriteFrame *pFrames, uint uFramesCount, uint &uAnim)
{
	if ( pAnimName == nullptr || pFrames == nullptr ||
		 uFramesCount == 0 || uNumb >= _aTextures.Count() )
	{
		return E_INVALIDARG;
	}

	string	s_anim_name( pAnimName );
	uint	u_idx = 0;

	while ( _CompareAnimNames( s_anim_name ) )
	{
		s_anim_name = pAnimName;
		s_anim_name << '(' << u_idx << ')';
		++u_idx;
	}

	_aTextures[uNumb].aAnimations.PushBack( TAnimation( s_anim_name, fFrameRate ) );

	uvec2 const	&s_dim	 = _aTextures[uNumb].sImage.vTexDim;
	uvec2 const	&s_frame = _aTextures[uNumb].sFrame;
	frames_array_t	&a_anim	 = _aTextures[uNumb].aAnimations.Back().aFrames;

	uint	u_count = (s_dim.x/s_frame.x) * (s_dim.y/s_frame.y);

	a_anim.Reserve( uFramesCount );

	for (uint i = 0; i < uFramesCount; ++i) {
		if ( pFrames[i].uIndex < u_count )
		{
			TSprite2D::TAnimFrame	s_animframe;

			s_animframe.uIndex = pFrames[i].uIndex;
			s_animframe.sColor = color4u( TRGBA( pFrames[i].uColor ).aRGBA );
			
			a_anim.PushBack( s_animframe );
		}
	}
	_bConverted = false;

	return S_OK;
}


HRESULT CALLBACK CSpriteConverter::RemoveAnimation(uint uNumb, const char *pAnimName)
{
	if ( uNumb >= _aTextures.Count() || pAnimName == nullptr )
		return E_INVALIDARG;

	string	str(pAnimName);

	for (uint i = 0; i < _aTextures[uNumb].aAnimations.Count(); ++i)
	{
		if ( str == _aTextures[uNumb].aAnimations[i].sName )
		{
			_aTextures[uNumb].aAnimations.Erase( i );
			_bConverted = false;
			return S_OK;
		}
	}

	return E_FAIL;
}


HRESULT CALLBACK CSpriteConverter::RemoveAnimationN(uint uNumb, uint uAnim)
{
	if ( uNumb >= _aTextures.Count() || uAnim >= _aTextures[uNumb].aAnimations.Count() )
		return E_INVALIDARG;

	_aTextures[uNumb].aAnimations.Erase( uAnim );
	_bConverted = false;
	return S_OK;
}


HRESULT CALLBACK CSpriteConverter::GetAnimationCount(uint uNumb, uint &uCount)
{
	if ( uNumb >= _aTextures.Count() )
		return E_INVALIDARG;

	uCount = _aTextures[uNumb].aAnimations.Count();
	return S_OK;
}


HRESULT CALLBACK CSpriteConverter::GetAnimation(uint uNumb, uint uAnim, char *pAnimName, uint uCharsCount, float &fFrameRate, TSpriteFrame *pFrames, uint uFramesSize, uint &uFramesCount)
{
	if ( uNumb >= _aTextures.Count() || uAnim >= _aTextures[uNumb].aAnimations.Count() ||
		 pAnimName == nullptr || pFrames == nullptr )
	{
		return E_INVALIDARG;
	}

	if ( uCharsCount > _aTextures[uNumb].aAnimations[uAnim].sName.Length() &&
		 uFramesSize > _aTextures[uNumb].aAnimations[uAnim].aFrames.Count() )
	{
		fFrameRate = _aTextures[uNumb].aAnimations[uAnim].fFrameRate;
		uFramesCount = _aTextures[uNumb].aAnimations[uAnim].aFrames.Count();
		memcpy( pAnimName, _aTextures[uNumb].aAnimations[uAnim].sName.cstr(), _aTextures[uNumb].aAnimations[uAnim].sName.Size() );
		memcpy( pFrames, _aTextures[uNumb].aAnimations[uAnim].aFrames.ptr(), _aTextures[uNumb].aAnimations[uAnim].aFrames.Size() );
		return S_OK;
	}
	return S_FALSE;
}


HRESULT CALLBACK CSpriteConverter::GetInfo(char *pBuffer, uint uCount)
{
	if ( pBuffer == nullptr || uCount == 0 )
		return E_INVALIDARG;

	if ( uCount > _sInfo.Length() )
	{
		memcpy( pBuffer, _sInfo.cstr(), _sInfo.Size() );
		return S_OK;
	}

	return E_FAIL;
}


HRESULT CALLBACK CSpriteConverter::GetFormat(TTextureFormat &sFormat)
{
	sFormat.uColorFormat	= ( _eFormat & e_tex_format::_CF_MASK ) >> e_tex_format::_CF_OFFSET;
	sFormat.uInternalFormat	= ( _eFormat & e_tex_format::_CIF_MASK ) >> e_tex_format::_CIF_OFFSET;
	sFormat.uValueType		= ( _eFormat & e_tex_format::_T_MASK ) >> e_tex_format::_T_OFFSET;
	
	GLint	swizzle[4];
	Image::GetSwizzle( _eSwizzle, swizzle );
	
	sFormat.sChannels.R		= GetChannel( swizzle[0] );
	sFormat.sChannels.G		= GetChannel( swizzle[1] );
	sFormat.sChannels.B		= GetChannel( swizzle[2] );
	sFormat.sChannels.A		= GetChannel( swizzle[3] );

	sFormat.bMipmaps		= _bGenMipmaps;
	sFormat.bCompressed		= false;
	
	return S_OK;
}


HRESULT CALLBACK CSpriteConverter::SetFormat(const TTextureFormat &sFormat)
{
	_eFormat	|= ( sFormat.uColorFormat << e_tex_format::_CF_OFFSET ) & e_tex_format::_CF_MASK;
	_eFormat	|= ( sFormat.uInternalFormat << e_tex_format::_CIF_OFFSET ) & e_tex_format::_CIF_MASK;
	_eFormat	|= ( sFormat.uValueType << e_tex_format::_T_OFFSET ) & e_tex_format::_T_MASK;

	GLint	swizzle[4] = {
		GetGLChannel( sFormat.sChannels.R ),
		GetGLChannel( sFormat.sChannels.G ),
		GetGLChannel( sFormat.sChannels.B ),
		GetGLChannel( sFormat.sChannels.A )
	};

	Image::SetSwizzle( swizzle, _eSwizzle );

	_bGenMipmaps	= sFormat.bMipmaps;
	_bConverted		= false;

	return S_OK;
}


HRESULT CALLBACK CSpriteConverter::GetParams(TSpriteParams &sParams)
{
	sParams = _sParams;
	return S_OK;
}


HRESULT CALLBACK CSpriteConverter::SetParams(const TSpriteParams &sParams)
{
	_sParams = sParams;
	_bConverted = false;
	return S_OK;
}


bool CSpriteConverter::_WriteToImage(TImage2D &sImage, const array<TSpritePos> &aSprites, uint uLevel)
{
	const uint	u_bpp		 = Image::GetPixelDataBPP( _eFormat );
	uint		u_dst_offset = 0,
				u_src_offset = 0;

	binary_buffer_t		temp;
	const uvec2		s_dim	= uvec2( sImage.vTexDim.x >> uLevel, sImage.vTexDim.y >> uLevel );

	for (uint i = 0; i < uLevel; ++i)
		u_dst_offset += sImage.aMipMaps[i];


	for (uint i = 0; i < aSprites.Count(); ++i)
	{
		const TImage2D	&img	= _aTextures[ aSprites[i].uNumb ].sImage;
		uvec2			img_dim	= img.vTexDim;


		// calc src offset & dim //
		for (uint j = 0; j < uLevel; ++j)
		{
			img_dim.x = img.vTexDim.x > 1 ? img.vTexDim.x >> 1 : 1;
			img_dim.y = img.vTexDim.y > 1 ? img.vTexDim.y >> 1 : 1;
			u_src_offset += img.aMipMaps[j];
		}


		// rotate image //
		if ( aSprites[i].iRotate == 1 )
		{
			temp.Resize( img.aMipMaps[uLevel], false );
			Memcpy2DRotate90( temp.ptr(), img.aData.ptr() + u_src_offset, img_dim.x, img_dim.y, u_bpp );
		}
		else
			temp.Copy( img.aData.ptr() + u_src_offset, img.aMipMaps[uLevel] );


		// add sprite //
		Memcpy2D( sImage.aData.ptr() + u_dst_offset, temp.ptr() + u_src_offset, u_bpp, s_dim.x, s_dim.y,
					img_dim.x, img_dim.y, aSprites[i].sPos.x, aSprites[i].sPos.y );
	}

	return true;
}


bool CSpriteConverter::_CompareAnimNames(const string &sAnimName) const
{
	for (uint i = 0; i < _aTextures.Count(); ++i)
	{
		for (uint j = 0; j < _aTextures[i].aAnimations.Count(); ++j)
		{
			if ( sAnimName == _aTextures[i].aAnimations[j].sName )
			{
				return true;
			}
		}
	}
	return false;
}


bool CSpriteConverter::_Convert(TSprite2D &sSprite, uvec2 &sLastDim)
{
	struct TSurfaceCmp
	{
		array< TSprImage >	*p_images;
		///
		TSurfaceCmp(array<TSprImage> *img): p_images(img) {}

		bool operator () (uint val1, uint val2)
		{
			const uvec2	&s1	= (*p_images)[val1].sImage.vTexDim,
							&s2	= (*p_images)[val2].sImage.vTexDim;

			return max( s1.x, s1.y ) > max( s2.x, s2.y );
		}
	};

	array< TSpritePos >		a_result;
	array< rectu >			a_free_rects;
	uint32_array_t			a_sorted;
	float					f_surface = 0.f;
	uvec2					s_max_size,
							s_res_size;
	e_tex_format::type		e_fmt	= _eFormat & ~e_tex_format::_CIF_MASK;

	sSprite.Clear();

	for (uint i = 0; i < _aTextures.Count(); ++i)
	{
		const uvec2	size = _aTextures[i].sImage.vTexDim + _sParams.uBorderSize;

		f_surface += float( size.x * size.y );

		if ( size.x > s_max_size.x )	s_max_size.x = size.x;
		if ( size.y > s_max_size.y )	s_max_size.y = size.y;

		if ( e_fmt != (_aTextures[i].sImage.eFormat & ~e_tex_format::_CIF_MASK) ) {
			LOG( "pixel data format mismatch", );
			return false;
		}

		a_sorted.PushBack(i);
	}

	TSurfaceCmp		s_cmp( &_aTextures );

	SelectSortC( a_sorted.ptr(), a_sorted.Count(), s_cmp );

	{
		s_res_size.x = 1 << GetPowOfTwo( s_max_size.x );
		s_res_size.y = 1 << GetPowOfTwo( s_max_size.y );

		while ( float( s_res_size.x*s_res_size.y ) < f_surface || All( sLastDim >= s_res_size ) )
		{
			if ( s_res_size.x <= s_res_size.y )
				s_res_size.x <<= 1;
			else
				s_res_size.y <<= 1;
		}
	}


	TSpriteConvertInfo		s_conv_info;

	float		f_surf		= float( s_res_size.x*s_res_size.y );
	s_conv_info.fEffective	= (f_surf - f_surface) / f_surf * 100.f;
	s_conv_info.uHeight		= s_res_size.y;
	s_conv_info.uWidth		= s_res_size.x;

	a_free_rects.PushBack( rectu( 0, 0, s_res_size.x, s_res_size.y ) );


	while ( !a_sorted.Empty() )
	{
		bool		b_res	 = false;
		const uvec2	img_size = _aTextures[ a_sorted.Back() ].sImage.vTexDim + _sParams.uBorderSize;
		s_conv_info.uAnimationsCount += _aTextures[ a_sorted.Back() ].aAnimations.Count();


		for (uint i = 0; i < a_free_rects.Count(); ++i)
		{
			const uvec2	size = a_free_rects[i].GetSize();

			if ( size.x >= img_size.x && size.y >= img_size.y )
			{
				const rectu		r = a_free_rects[i];

				a_free_rects.Erase( i );
				a_result.PushBack( TSpritePos( rectu( r.x, r.y, r.x+img_size.x, r.y+img_size.y ), a_sorted.Back(), 0 ) );

				if ( size.x > img_size.x )
					a_free_rects.PushBack( rectu( r.x + img_size.x, r.y, r.w, r.y + img_size.y ) );
				
				if ( size.y > img_size.y )
					a_free_rects.PushBack( rectu( r.x, r.y + img_size.y, r.w, r.h ) );
				
				b_res = true;
				break;
			}
			else

			if ( size.x >= img_size.y && size.y >= img_size.x )
			{
				const rectu		r = a_free_rects[i];

				a_free_rects.Erase( i );
				a_result.PushBack( TSpritePos( rectu( r.x, r.y, r.x+img_size.y, r.y+img_size.x ), a_sorted.Back(), 1 ) );

				if ( size.x > img_size.y )
					a_free_rects.PushBack( rectu( r.x + img_size.y, r.y, r.w, r.y + img_size.x ) );
				
				if ( size.y > img_size.x )
					a_free_rects.PushBack( rectu( r.x, r.y + img_size.x, r.w, r.h ) );
				
				b_res = true;
				break;
			}
		
		}
		
		if ( !b_res )
		{
			sLastDim = s_res_size;
			LOG( "can't get free rectangle in image.", );
			return false;
		}

		a_sorted.PopBack();
	}


	// Create Image //
	TImage2D	s_image;

	s_image.vTexDim		= s_res_size;
	s_image.eFormat		= _eFormat;
	s_image.eSwizzle	= _eSwizzle;
	s_image.bCompressed	= false;

	_bGenMipmaps = false;

	uint	u_mm_count	= _bGenMipmaps ? GetNumMipmaps( s_image.vTexDim ) : 1;
	bool	res			= true;
	uint	u_bpp		= Image::GetPixelDataBPP( _eFormat );

	for (uint i = 0; i < u_mm_count; ++i)
	{
		const uint		u_size = (s_res_size.x >> i) * (s_res_size.y >> i) * u_bpp;
		s_image.aData.Resize( u_size, false );
		s_image.aMipMaps.PushBack( u_size );
	}

	// set background color
	uint	u_colors = Image::GetColorChannels( _eFormat );

	switch ( u_colors )
	{
		case 1 :
			Memset<TRed>( (TRed*)s_image.aData.ptr(), s_image.aData.Size() / sizeof(TRed), TRGBA( _sParams.uBorderColor ).R() );
			break;

		case 2 :
			Memset<TRG>( (TRG*)s_image.aData.ptr(), s_image.aData.Size() / sizeof(TRG), TRGBA( _sParams.uBorderColor ).RG() );
			break;

		case 3 :
			Memset<TRGB>( (TRGB*)s_image.aData.ptr(), s_image.aData.Size() / sizeof(TRGB), TRGBA( _sParams.uBorderColor ).RGB() );
			break;

		case 4 :
			Memset<TRGBA>( (TRGBA*)s_image.aData.ptr(), s_image.aData.Size() / sizeof(TRGBA), TRGBA( _sParams.uBorderColor ) );
			break;

		default :
			return false;
	};


	// TODO: gen mipmaps for sprites

	for (uint i = 0; i < u_mm_count && res; ++i)
	{
		res = _WriteToImage( s_image, a_result, i );
	}

	sSprite.sImage.Swap( s_image );


	// generate animation frames //

	for (uint i = 0; i < a_result.Count(); ++i)
	{
		TSprImage const &	img	= _aTextures[ a_result[i].uNumb ];
		uvec2 const		s_fr_count( img.sImage.vTexDim.x/img.sFrame.x, img.sImage.vTexDim.y/img.sFrame.y );
		uint const			u_count = s_fr_count.x * s_fr_count.y;
		usize const			u_pos	= sSprite.aTexcoords.Count();

		for (uint j = 0; j < u_count; ++j)
		{
			rectu	s_frame( a_result[i].sPos.x, a_result[i].sPos.y,
							 a_result[i].sPos.x, a_result[i].sPos.y );

			s_frame += ( img.sFrame.x + (j%s_fr_count.x), img.sFrame.y + (j/s_fr_count.x) );

			sSprite.aTexcoords.PushBack( rectf(	(float)s_frame.x / (float)s_res_size.x,
												(float)s_frame.y / (float)s_res_size.y,
												(float)s_frame.w / (float)s_res_size.x,
												(float)s_frame.h / (float)s_res_size.y ) );
		}

		for (uint j = 0; j < img.aAnimations.Count(); ++j)
		{
			sSprite.aAnimation.PushBack( TSprite2D::TAnimInfo( img.aAnimations[j].sName.cstr(),
				sSprite.aFrames.Count(), img.aAnimations[j].aFrames.Count(), img.aAnimations[j].fFrameRate ) );

			for (uint k = 0; k < img.aAnimations[j].aFrames.Count(); ++k)
			{
				TSprite2D::TAnimFrame	s_animframe( img.aAnimations[j].aFrames[k] );

				s_animframe.uIndex += u_pos;

				sSprite.aFrames.PushBack( s_animframe );
			}
		}
	}

	_sInfo.Clear();
	_sInfo << "width:        " << s_conv_info.uWidth << "\x00D\x00A";
	_sInfo << "height:       " << s_conv_info.uHeight << "\x00D\x00A";
	_sInfo << "free surface: " << s_conv_info.fEffective << " %\x00D\x00A";
	_sInfo << "anim count:   " << sSprite.aAnimation.Count() << "\x00D\x00A";
	_sInfo << "frame count:  " << sSprite.aTexcoords.Count() << "\x00D\x00A";

	return true;
}
